﻿using System;
using System.Collections.Generic;
using Sissonix.Infrastructure.RepositoryFramework;
using System.Data.Objects.DataClasses;
using System.Transactions;
using Sissonix.Infrastructure.DomainBase;

namespace Sissonix.Infrastructure
{
    public class UnitOfWork : IUnitOfWork
    {
        private Guid key;
        //MWS private IClientTransactionRepository clientTransactionRepository;
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> addedEntities;
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> changedEntities;
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> deletedEntities;

        public UnitOfWork()
        {
            this.key = Guid.NewGuid();
            //MWS this.clientTransactionRepository = ClientTransactionRepositoryFactory.GetTransactionRepository();
            this.addedEntities = new Dictionary<IAggregateRoot, 
                                     IUnitOfWorkRepository>();
            this.changedEntities = new Dictionary<IAggregateRoot, 
                                       IUnitOfWorkRepository>();
            this.deletedEntities = new Dictionary<IAggregateRoot, 
                                       IUnitOfWorkRepository>();
        }

        #region IUnitOfWork Members

        public Dictionary<IAggregateRoot, IUnitOfWorkRepository> Adds
        {
            get { return this.addedEntities; }
        }

        public Dictionary<IAggregateRoot, IUnitOfWorkRepository> Changes
        {
            get { return this.changedEntities; }
        }

        public Dictionary<IAggregateRoot, IUnitOfWorkRepository> Deletes
        {
            get { return this.deletedEntities; }
        }

        public bool HasRecords
        {
            get
            {
                return (this.addedEntities.Count + 
                    this.changedEntities.Count +
                    this.deletedEntities.Count > 0);
            }
        }

        public void RegisterAdded(IAggregateRoot entity, 
            IUnitOfWorkRepository repository)
        {
            this.addedEntities.Add(entity, repository);
        }

        public void RegisterChanged(IAggregateRoot entity, 
            IUnitOfWorkRepository repository)
        {
            this.changedEntities.Add(entity, repository);
        }

        public void RegisterRemoved(IAggregateRoot entity, 
            IUnitOfWorkRepository repository)
        {
            this.deletedEntities.Add(entity, repository);
        }

        public void Commit()
        {
            HashSet<IUnitOfWorkRepository> repos = new HashSet<IUnitOfWorkRepository>();
            bool doCommit = true;
            using (TransactionScope scope = new TransactionScope())
            {

                try
                {
                    foreach (IAggregateRoot entity in this.deletedEntities.Keys)
                    {
                        this.deletedEntities[entity].PersistDeletedItem(entity);
                        repos.Add(this.deletedEntities[entity]);
                    }

                    foreach (IAggregateRoot entity in this.addedEntities.Keys)
                    {
                        this.addedEntities[entity].PersistNewItem(entity);
                        repos.Add(this.addedEntities[entity]);
                    }

                    foreach (IAggregateRoot entity in this.changedEntities.Keys)
                    {
                        this.changedEntities[entity].PersistUpdatedItem(entity);
                        repos.Add(this.changedEntities[entity]);
                    }

                    foreach (IUnitOfWorkRepository repo in repos)
                        repo.CommitPersistedItems();
                }
                catch (Exception e)
                {
                    doCommit = false;
                }
                if (doCommit)
                    scope.Complete();
            }
            if (doCommit)
            {
                this.deletedEntities.Clear();
                this.addedEntities.Clear();
                this.changedEntities.Clear();
                this.key = Guid.NewGuid();
            }
        }

        public object Key
        {
            get { return this.key; }
        }

        //MWS
        //public IClientTransactionRepository ClientTransactionRepository
        //{
        //    get { return this.clientTransactionRepository; }
        //}

        #endregion
    }
}
